﻿using System;
using System.Collections.Generic;

namespace CQRSFramework.Common.Components
{
    /// <summary>
    /// Dependency injection container
    /// </summary>
    public class ObjectContainer
    {
        public static IObjectContainer Current;

        /// <summary>
        /// set dependency injection container
        /// </summary>
        /// <param name="objectContainer">the class whitch impletement IObjectContainer</param>
        public static void SetContainer(IObjectContainer objectContainer)
        {
            Current = objectContainer;
        }

        /// <summary>
        /// Builder the container
        /// </summary>
        public static void BuilderContainer()
        {
            Current.Build();
        }

        public static void RegisterType(Type implementationType, string serviceName = null, LifeStyle life = LifeStyle.Singleton)
        {
            Current.RegisterType(implementationType, serviceName, life);
        }

        public static void RegisterType(Type serviceType, Type implementationType, string serviceName = null, LifeStyle life = LifeStyle.Singleton)
        {
            Current.RegisterType(serviceType, implementationType, serviceName, life);
        }

        public static void Register<TService, TImplementer>(LifeStyle life = LifeStyle.Singleton, string serviceName = null) where TService : class
            where TImplementer : class, TService
        {
            Current.Register<TService, TImplementer>(serviceName, life);
        }

        public static void RegisterInstance<TService, TImplementer>(TImplementer instance, string serviceName = null) where TService : class
            where TImplementer : class, TService
        {
            Current.RegisterInstance<TService, TImplementer>(instance, serviceName);
        }

        public static void RegisterGeneric(Type serviceType, Type implementationType, string serviceName = null, LifeStyle life = LifeStyle.Singleton)
        {
            Current.RegisterGeneric(serviceType, implementationType);
        }
        /// <summary>Resolve a service.
        /// </summary>
        /// <typeparam name="TService">The service type.</typeparam>
        /// <returns>The component instance that provides the service.</returns>
        public static TService Resolve<TService>() where TService : class
        {
            return Current.Resolve<TService>();
        }

        /// <summary>Resolve a service.
        /// </summary>
        /// <param name="serviceType">The service type.</param>
        /// <returns>The component instance that provides the service</returns>
        public static object Resolve(Type serviceType)
        {
            return Current.Resolve(serviceType);
        }

        /// <summary>Resolve a service or null if the service is not registed
        /// </summary>
        /// <param name="serviceType">The service type or null</param>
        /// <returns>The component instance that provides the service or null if the service is not registed</returns>
        public static object ResolveOptional(Type serviceType)
        {
            return Current.ResolveOptional(serviceType);
        }

        /// <summary>
        /// Resolve a service or null with the servcieName
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="serviceName">The serviceName</param>
        /// <returns></returns>
        public static TService ResolveNamed<TService>(string serviceName) where TService : class
        {
            return Current.ResolveNamed<TService>(serviceName);
        }

        /// <summary>
        /// Resolve a service by serviceName and serviceType
        /// </summary>
        /// <param name="serviceName">the serivce name</param>
        /// <param name="serviceType">the service type</param>
        /// <returns></returns>
        public static object ResolveNamed(string serviceName, Type serviceType)
        {
            return Current.ResolveNamed(serviceName, serviceType);
        }

        /// <summary>Resolve all given service.
        /// </summary>
        /// <param name="serviceType">The given service type.</param>
        /// <returns>The all component instance that provides the service</returns>
        public static IEnumerable<object> ResolveAll(Type serviceType)
        {
            return Current.ResolveAll(serviceType);
        }
    }

    /// <summary>An enum to description the lifetime of a component.
    /// </summary>
    public enum LifeStyle
    {
        /// <summary>Represents a component is a transient component.
        /// </summary>
        Transient,
        /// <summary>Represents a component is a singleton component.
        /// </summary>
        Singleton
    }
}
